package com.webserver.controller;

import com.webserver.annotation.Controller;
import com.webserver.annotation.RequestMapping;
import com.webserver.entity.User;
import com.webserver.http.MyHttpRequest;
import com.webserver.http.MyHttpResponse;
import org.apache.log4j.Logger;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

/**
 * 作者：JustOne
 * 微信：Andylau2020smile
 * 抖音：JustOne2018
 * 日期：2022/6/18 15:42
 */
//类似于旧版的RegServler
@Controller
public class UserController {
    ////在当前目录下创建一个 users目录，用于保存所有的user.obj
    private static File userDir;
    ////日志，注意导包是：import org.apache.log4j.Logger;
    private static final Logger logger = Logger.getLogger(UserController.class);
    static {
        userDir = new File("./users");//指定目录，如果没有就创建
        if( ! userDir.exists()){
            userDir.mkdirs();
        }
    }

    ////执行注册
    @RequestMapping("/myweb/doRegister")
    public void reg(MyHttpRequest myHttpRequest, MyHttpResponse myHttpResponse){
        logger.info("开始处理注册");
        //step1:获取用户的注册数据
        String userName = myHttpRequest.getParameter("username");//该参数必须与前端页面的name属性保持一至
        String passWord = myHttpRequest.getParameter("password");
        String nickName = myHttpRequest.getParameter("nickname");
        String ageStr = myHttpRequest.getParameter("age");

        //System.out.println("controller收到的数据是："+userName+","+passWord+","+nickName+","+ageStr);
        logger.debug("controller收到的数据是："+userName+","+passWord+","+nickName+","+ageStr);

        //step2:检验用户的注册数据
        if(userName.isEmpty() || passWord.isEmpty() || nickName.isEmpty() || ageStr.isEmpty() || !ageStr.matches("[0-9]+")){
            //原来是这样内部跳转，从第15版起就改成下面的 重定向
            //响应注册失败"regError.html"页面给用户
            //File file = new File(DispatcherServlet.staticDir,"/myweb/regError.html");
            //myHttpResponse.setFile(file);

            //System.out.println("注册失败，原因：数据检验没有通过");
            logger.info("注册失败，原因：数据检验没有通过");

            myHttpResponse.sendRedirect("/myweb/regError.html");//重定向
            return;
        }

        //step03:绑定用户的注册数据
        int age = Integer.parseInt(ageStr);
        User user = new User(userName, passWord, nickName, age);
        File userFile = new File(userDir, userName + ".obj");

        //step04:检查用户是否存在，如果存入就跳转到haveUser.html页面
        if(userFile.exists()){
            //原来是这样内部跳转，从第15版起就改成下面的 重定向
            //File file = new File(DispatcherServlet.staticDir, "/myweb/haveUser.html");
            //myHttpResponse.setFile(file);
            myHttpResponse.sendRedirect("/myweb/haveUser.html");//重定向
            return;
        }

        //step05:写入用户的注册数据
        try(FileOutputStream fos = new FileOutputStream(userFile);
            ObjectOutputStream oos = new ObjectOutputStream(fos);)
        {
            oos.writeObject(user);
            //原来是这样内部跳转，从第15版起就改成下面的 重定向
            //File file = new File(DispatcherServlet.staticDir,"/myweb/regSuccess.html");
            //myHttpResponse.setFile(file);
            myHttpResponse.sendRedirect("/myweb/regSuccess.html");//重定向
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    ////执行登录
    @RequestMapping("/myweb/doLogin")
    public void login(MyHttpRequest myHttpRequest, MyHttpResponse myHttpResponse){
        logger.info("开始执行登录请求");
        //step1:获取用户的登录数据
        //数据是页面通过地址栏参数条提交的，我们手写的MyHttpRequest解析后放到map集合中的
        String _userName = myHttpRequest.getParameter("username");//这个参数要与前端name属性的值保持一致
        String _passWord = myHttpRequest.getParameter("password");
        String _code = myHttpRequest.getParameter("code").toLowerCase();//验证码转小写

        //step2:检验用户的登录数据  //如果用户没有输入内容就提示输入的信息有误
        String code = "abcd";//正确的验证码转小写
        if( _userName.isEmpty() || _passWord.isEmpty() || _code.isEmpty() || ! _code.equals(code)){
            //原来是这样内部跳转，从第15版起就改成下面的 重定向
            //File file = new File(DispatcherServlet.staticDir,"/myweb/loginInfoError.html");
            //myHttpResponse.setFile(file);
            myHttpResponse.sendRedirect("/myweb/loginInfoError.html");//重定向
            return;
        }

        //step3:比对用户的登录数据(用户存在 && 验证码正确)
        File userFile = new File(userDir, _userName+".obj");
        if(userFile.exists()){ //该文件存在，说明有该用户，就可以比对密码了
            //之前学过，反序列化，可以带学生回顾《My034_IO_v01 / pack01 / Demo10_对象流》
            try(ObjectInputStream ois = new ObjectInputStream(new FileInputStream(userFile))){
                User user = (User)(ois.readObject());
                if(user.getPassWord().equals(_passWord)){
                    //原来是这样内部跳转，从第15版起就改成下面的 重定向
                    //File file = new File(DispatcherServlet.staticDir,"/myweb/loginSuccess.html");
                    //myHttpResponse.setFile(file);
                    myHttpResponse.sendRedirect("/myweb/loginSuccess.html");
                    return;
                }
            } catch (Exception e){
                e.printStackTrace();
            }
        }

        //如果能走到这里，说明登录失败了，有可能是：1,用户名不对， 2,密码不对， 3,验证码不对
        //File file = new File(DispatcherServlet.staticDir,"/myweb/loginFail.html");
        //myHttpResponse.setFile(file);
        logger.error("登录失败，原因：数据检验没有通过");
        myHttpResponse.sendRedirect("/myweb/loginFail.html");//重定向
    }

    ////执行用户列表
    @RequestMapping("/myweb/showAll")
    public void showAll(MyHttpRequest myHttpRequest, MyHttpResponse myHttpResponse){
        //原来：System.out.println("开始处理动态页面");
        logger.info("开始处理动态页面");

        //定义集合用于存放所有的user对象
        List<User> userList = new ArrayList<>();
        //定义过滤器(是文件，并以.obj结尾)，可以回顾Lambda表达式
        FileFilter filter = (f) -> f.isFile() && f.getName().endsWith(".obj");
        //获取user目录下所有的 符合过滤器条件的文件
        File[] users = userDir.listFiles(filter);
        //以上两句可以简写成： File[] users = userDir.listFiles(f -> f.isFile() && f.getName().endsWith(".obj"));

        //将反序列化对象存入userList备用
        for(File userFile : users){
            try(ObjectInputStream ois = new ObjectInputStream(new FileInputStream( userFile ))){
                User user = (User)ois.readObject();
                //原来：System.out.println("user = " + user);
                logger.debug("user = " + user);
                userList.add(user);
            }catch (IOException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                //原来：e.printStackTrace();
                logger.error(e.getMessage(),e);
            }
        }

        //动态拼接字符串
        StringBuilder htmlStr = new StringBuilder();

        htmlStr.append("<!DOCTYPE html>");
        htmlStr.append("<html lang='zh'>");
        htmlStr.append("<head>");
        htmlStr.append("<meta charset='UTF-8'>");
        htmlStr.append("<title>用户列表</title>");
        htmlStr.append("</head>");
        htmlStr.append("<body>");
        htmlStr.append("<h1>用户列表</h1>");
        htmlStr.append("<table border='1'>");
        htmlStr.append("<tr><td>用户名</td><td>密码</td><td>昵称</td><td>年龄</td></tr>");

        for(User user: userList){
            htmlStr.append("<tr>");
            htmlStr.append("<td>"+user.getUserName()+"</td>");
            htmlStr.append("<td>"+user.getPassWord()+"</td>");
            htmlStr.append("<td>"+user.getNickName()+"</td>");
            htmlStr.append("<td>"+user.getAge()+"</td>");
            htmlStr.append("</tr>");
        }
        htmlStr.append("</table>");
        htmlStr.append("</body>");
        htmlStr.append("</html>");

        //把长长的字符串转成字节数组，设置给响应对象当成正文。
        //字符集可以写字符串"UTF-8"，但是需要处理异常，用系统自己定义好的就不需要处理。
        //有的版本可能是先把字个长字符串写成本地文件，再响应给浏览器，那样不好，因为要先写，再读，浪费效率
        //像现在这样，直接向字符串从内存从发给浏览器就行了
        byte[] data = htmlStr.toString().getBytes(StandardCharsets.UTF_8);
        //响应给浏览器
        myHttpResponse.setData(data);
    }

}


























